package com.dianplus.biz.auth.service;

import com.dianplus.biz.auth.domain.SysLogin;
import com.dianplus.biz.auth.domain.SysRole;
import com.dianplus.biz.auth.repository.SysLoginRepository;
import com.dianplus.biz.auth.repository.SysRoleRepository;
import com.dianplus.biz.auth.service.dto.LoginDTO;
import com.dianplus.biz.config.Util.RandomUtil;
import com.dianplus.biz.security.SecurityUtils;
import com.dianplus.biz.security.exception.InvalidPasswordException;
import com.dianplus.biz.security.exception.UsernameAlreadyUsedException;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Service class for managing users.
 */
@Slf4j
@Service
@Transactional
public class LoginService {

    @Autowired
    private SysLoginRepository sysLoginRepository;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private SysRoleRepository sysRoleRepository;


    public SysLogin registerUser(LoginDTO loginDTO, String password) {
        sysLoginRepository.findOneWithRolesByLogin(loginDTO.getLogin().toLowerCase()).ifPresent(existingUser -> {
//            boolean removed = removeNonActivatedUser(existingUser);
//            if (!removed) {
            throw new UsernameAlreadyUsedException();
            //  }
        });
        SysLogin newUser = SysLogin.builder()
                .login(loginDTO.getLogin().toLowerCase())
                .password(passwordEncoder.encode(password))
                .firstName(loginDTO.getFirstName())
                .lastName(loginDTO.getLastName())
                .email(StringUtils.isNotBlank(loginDTO.getEmail()) ? loginDTO.getEmail() : null)
                .imageUrl(loginDTO.getImageUrl())
                .valid(false)
                .build();
        sysLoginRepository.save(newUser);
        log.debug("Created Information for User: {}", newUser);
        return newUser;
    }


    public SysLogin createUser(LoginDTO loginDTO) {
        SysLogin newUser = SysLogin.builder()
                .login(loginDTO.getLogin().toLowerCase())
                .password(passwordEncoder.encode(RandomUtil.generatePassword()))
                .firstName(loginDTO.getFirstName())
                .lastName(loginDTO.getLastName())
                .email(StringUtils.isNotBlank(loginDTO.getEmail()) ? loginDTO.getEmail() : null)
                .imageUrl(loginDTO.getImageUrl())
                .valid(false)
                .build();
        if(loginDTO.getRoleIds() != null) {
            Set<SysRole> sysRoles = loginDTO.getRoleIds().stream()
                    .map(sysRoleRepository::findById)
                    .filter(Optional::isPresent)
                    .map(Optional::get)
                    .collect(Collectors.toSet());
            newUser.setRoles(sysRoles);
        }
        sysLoginRepository.save(newUser);
        log.debug("Created Information for User: {}", newUser);
        return newUser;
    }

    /**
     * Update basic information (first name, last name, email, language) for the current user.
     *
     * @param firstName first name of user.
     * @param lastName  last name of user.
     * @param email     email id of user.
     * @param imageUrl  image URL of user.
     */
    public void updateUser(String firstName, String lastName, String email, String imageUrl) {
        SecurityUtils.getCurrentUserLogin()
                .flatMap(sysLoginRepository::findOneByLogin)
                .ifPresent(user -> {
                    user.setFirstName(firstName);
                    user.setLastName(lastName);
                    user.setEmail(email.toLowerCase());
                    user.setImageUrl(imageUrl);
                    log.debug("Changed Information for User: {}", user);
                });
    }

    public void deleteUser(String login) {
        sysLoginRepository.findOneByLogin(login).ifPresent(user -> {
            sysLoginRepository.delete(user);
            log.debug("Deleted User: {}", user);
        });
    }

    public void changePassword(String currentClearTextPassword, String newPassword) {
        SecurityUtils.getCurrentUserLogin()
                .flatMap(sysLoginRepository::findOneByLogin)
                .ifPresent(user -> {
                    String currentEncryptedPassword = user.getPassword();
                    if(!passwordEncoder.matches(currentClearTextPassword, currentEncryptedPassword)) {
                        throw new InvalidPasswordException();
                    }
                    String encryptedPassword = passwordEncoder.encode(newPassword);
                    user.setPassword(encryptedPassword);
                    log.debug("Changed password for User: {}", user);
                });
    }

}
